/**
 * Copyright (c) 2020 lizebang
 *
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

package cmd

import (
	"fmt"
	"os"
	"strings"
	"syscall"

	"gitee.com/banggua/ggtsync/cmdutil"
	"gitee.com/banggua/ggtsync/config"
	"gitee.com/banggua/ggtsync/handler"
	"gitee.com/banggua/ggtsync/logger"
	"gitee.com/banggua/ggtsync/plugin"
)

const (
	configStartSuccess = `ggtsync: successfully start
`
	configStartFailure = `ggtsync: %v
ggtsync: fail to start
`
)

func getpid(execname string) (int, error) {
	var (
		pid int
		cur = os.Getpid()
	)

	pcs, err := cmdutil.RunOutput("", "ps", "-eo", "pid,comm")
	if err != nil {
		return -1, err
	}

	for _, pc := range pcs {
		if strings.Contains(pc, execname) {
			_, err = fmt.Sscanf(pc, "%d", &pid)
			if err != nil {
				return -1, err
			}
			if pid == cur {
				continue
			}
			return pid, nil
		}
	}
	return -1, nil
}

func start(filename string) {
	pid, err := getpid(execname)
	if err != nil {
		logger.Errorf(configStartFailure, err)
		os.Exit(1)
	} else if pid > 0 {
		logger.Errorf(configStartFailure, fmt.Sprintf("the program has started, please run `ggtsync -s quit` or `kill -9 %d` and then try it again", pid))
		os.Exit(1)
	}

	err = config.Load(filename)
	if err != nil {
		logger.Errorf(configStartFailure, err)
		handler.Templet()
		plugin.Templet()
		os.Exit(1)
	}

	projects := config.GetProjects()
	err = handler.Test(projects)
	if err != nil {
		logger.Errorf(configStartFailure, err)
		os.Exit(1)
	}

	for _, project := range projects {
		handler.Handle(&project)
	}
	handler.Wait()
}

const (
	configReloadSuccess = `%s: config successfully load
`
	configReloadFailure = `%s: %v
%s: fail to reload config
`
)

func reload() {
	pid, err := getpid(execname)
	if err != nil || pid < 0 {
		logger.Errorf(configReloadFailure, execname, err, execname)
		os.Exit(1)
	}

	err = syscall.Kill(pid, syscall.SIGUSR1)
	if err != nil {
		logger.Errorf(configReloadFailure, execname, err, execname)
		os.Exit(1)
	}

	logger.Infof(configReloadSuccess, execname)
	os.Exit(0)
}

const (
	configQuitSuccess = `%s: successfully quit
`
	configQuitFailure = `%s: %v
%s: fail to quit, please use "kill" command to exit manually
`
)

func quit() {
	pid, err := getpid(execname)
	if err != nil || pid < 0 {
		logger.Errorf(configQuitFailure, execname, err, execname)
		os.Exit(1)
	}

	err = syscall.Kill(pid, syscall.SIGUSR2)
	if err != nil {
		logger.Errorf(configQuitFailure, execname, err, execname)
		os.Exit(1)
	}

	logger.Infof(configQuitSuccess, execname)
	os.Exit(0)
}

func Signal(signal, filename string) {
	switch signal {
	case "start":
		start(filename)
	case "reload":
		reload()
	case "quit":
		quit()
	}
}
